/*
Modifications made by: Paul Stelly & Ricardo Colas
Modifications for Project 3:
void List();

Additions for Project 3:
void List2();
*/

// directory.cc 
//	Routines to manage a directory of file names.
//
//	The directory is a table of fixed length entries; each
//	entry represents a single file, and contains the file name,
//	and the location of the file header on disk.  The fixed size
//	of each directory entry means that we have the restriction
//	of a fixed maximum size for file names.
//
//	The constructor initializes an empty directory of a certain size;
//	we use ReadFrom/WriteBack to fetch the contents of the directory
//	from disk, and to write back any modifications back to disk.
//
//	Also, this implementation has the restriction that the size
//	of the directory cannot expand.  In other words, once all the
//	entries in the directory are used, no more files can be created.
//	Fixing this is one of the parts to the assignment.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include "copyright.h"
#include "utility.h"
#include "filehdr.h"
#include "directory.h"
#include "filesys.h"

#include "system.h"



//begin mod
DirectoryEntry* 
Directory::getTable(){

 return table;
}
//end of mod

//----------------------------------------------------------------------
// Directory::Directory
//      Initialize a directory; initially, the directory is completely
//      empty.  If the disk is being formatted, an empty directory
//      is all we need, but otherwise, we need to call FetchFrom in order
//      to initialize it from disk.
//
//      "size" is the number of entries in the directory
//---------------------------------------------------------------------- 
Directory::Directory(int size)
{
    table = new DirectoryEntry[size];
    tableSize = size;
    for (int i = 0; i < tableSize; i++)
        table[i].inUse = FALSE;
}
//----------------------------------------------------------------------
// Directory::~Directory
//      De-allocate directory data structure.
//----------------------------------------------------------------------

Directory::~Directory()
{ 
    delete [] table;
} 

//----------------------------------------------------------------------
// Directory::FetchFrom
//      Read the contents of the directory from disk.
//
//      "file" -- file containing the directory contents
//----------------------------------------------------------------------

void
Directory::FetchFrom(OpenFile *file)
{
    (void) file->ReadAt((char *)table, tableSize * sizeof(DirectoryEntry), 0);

        
}

//----------------------------------------------------------------------
// Directory::WriteBack
//      Write any modifications to the directory back to disk
//
//      "file" -- file to contain the new directory contents
//----------------------------------------------------------------------

void
Directory::WriteBack(OpenFile *file)
{
    (void) file->WriteAt((char *)table, tableSize * sizeof(DirectoryEntry), 0);
}

//----------------------------------------------------------------------
// Directory::FindIndex
//      Look up file name in directory, and return its location in the table of
//      directory entries.  Return -1 if the name isn't in the directory.
//
//      "name" -- the file name to look up
//----------------------------------------------------------------------

int
Directory::FindIndex(char *name)
{
   //     printf("tableSize is %d in FindIndex\n", tableSize);

   //     for(int j = 0; j < tableSize; j++)
    //            if(table[j].inUse)
    //            printf("Table[j].name is %s\n", table[j].name);
    for (int i = 0; i < tableSize; i++)
        if (table[i].inUse && !strncmp(table[i].name, name, FileNameMaxLen))
            return i;
    return -1;          // name not in directory
}

//----------------------------------------------------------------------
// Directory::Find
//      Look up file name in directory, and return the disk sector number
//      where the file's header is stored. Return -1 if the name isn't 
//      in the directory.
//
//      "name" -- the file name to look up
//----------------------------------------------------------------------

int
Directory::Find(char *name)
{
    int i = FindIndex(name);

    if (i != -1)
        return table[i].sector;
    return -1;
}

//----------------------------------------------------------------------
// Directory::Add
//      Add a file into the directory.  Return TRUE if successful;
//      return FALSE if the file name is already in the directory, or if
//      the directory is completely full, and has no more space for
//      additional file names.
//
//      "name" -- the name of the file being added
//      "newSector" -- the disk sector containing the added file's header
//----------------------------------------------------------------------

bool
Directory::Add(char *name, int newSector)
{ 

    if (FindIndex(name) != -1)
        return FALSE;

    for (int i = 0; i < tableSize; i++)
        if (!table[i].inUse) {
            table[i].inUse = TRUE;
            strncpy(table[i].name, name, FileNameMaxLen); 
            table[i].type = "File";
            table[i].sector = newSector;
      //  for(int j = 0; j < tableSize; j++)
      //          if(table[j].inUse)
     //           printf("Table[i].name is %s\n", table[j].name);
	if(fileSystem->addDirToTree((table + i)))
	//	printf("added to tree\n")
        return TRUE;
        }
    return FALSE;       // no space.  Fix when we have extensible files.
}


bool
Directory::AddDir(char *name, int newSector)
{ 
    if (FindIndex(name) != -1)
        return FALSE;

    for (int i = 0; i < tableSize; i++){
	
        if (!table[i].inUse) {
            table[i].inUse = TRUE;
            strncpy(table[i].name, name, FileNameMaxLen); 
                        table[i].type = "Directory";
            table[i].sector = newSector;
	if(fileSystem->addDirToTree((table + i)))
	//	printf("added to tree\n")
        return TRUE;
        }	
	}	
	
	/*tableSize = tableSize + 1;
	ptr = &table;
	for (int i = 0; i < tableSize; i++){
	
        if (!*(ptr+i).inUse) {
            *(ptr+i).inUse = TRUE;
            strncpy(*(ptr+i).name, name, FileNameMaxLen); 
            *(ptr+i).type = "Directory";
            *(ptr+i).sector = newSector;
        return TRUE;
        }	
	}*/
	
	//how number of entries more than disk space.
    return FALSE;       // no space.  Fix when we have extensible files.
}

//----------------------------------------------------------------------
// Directory::Remove
//      Remove a file name from the directory.  Return TRUE if successful;
//      return FALSE if the file isn't in the directory. 
//
//      "name" -- the file name to be removed
//----------------------------------------------------------------------

bool
Directory::Remove(char *name)
{ 
    int i = FindIndex(name);
	
    if (i == -1)
        return FALSE;           // name not in directory
	for(int s = 0; s <= FileNameMaxLen; s++)
    table[i].name[s] = table[tableSize-1].name[s];
	table[i].type = table[tableSize-1].type;
	table[i].sector = table[tableSize-1].sector;
	table[tableSize-1].inUse = FALSE;
    return TRUE;        
}

//----------------------------------------------------------------------
// Directory::List
//      List all the file names in the directory. 
//----------------------------------------------------------------------

//Begin Modifications by Paul Stelly and Ricardo Colas
void
Directory::List()
{
        FileHeader *hdr = new FileHeader;
        printf("Name          Size         Type\n");
   for (int i = 0; i < tableSize; i++)
        if (table[i].inUse)
        {
                hdr->FetchFrom(table[i].sector);
            printf("%s", table[i].name);
                printf("            %d", hdr->FileLength());
                printf("            %s\n", table[i].type);
        }
   delete hdr;
}
//End Modifications by Paul Stelly and Ricardo Colas
//Begin Additions by Paul Stelly and Ricardo Colas
void
Directory::List2()
{
        FileHeader *hdr = new FileHeader;
        printf("Name\n");
    for (int i = 0; i < tableSize; i++)
        if (table[i].inUse)
        {
                hdr->FetchFrom(table[i].sector);
            printf("%s\n", table[i].name);
        }
   delete hdr;
}
//End Additions by Paul Stelly and Ricardo Colas
//----------------------------------------------------------------------
// Directory::Print
//      List all the file names in the directory, their FileHeader locations,
//      and the contents of each file.  For debugging.
//----------------------------------------------------------------------

void
Directory::Print()
{ 
    FileHeader *hdr = new FileHeader;

    printf("Directory contents:\n");
    for (int i = 0; i < tableSize; i++)
        if (table[i].inUse) {
            printf("Name: %s, Sector: %d\n", table[i].name, table[i].sector);
            hdr->FetchFrom(table[i].sector);
            hdr->Print();
        }
    printf("\n");
    delete hdr;
}

